Keygen Tutorial 3
				   Yes123 '99
---[ WARNING ]--------------------------------------------------------------------------------

This Tutorial is for education purpose only. I wrote it to allow you to understand how are
coded some protections schemes in software. I didn't make it to allow you to use the target
program without paying the author. If you plan to use these programs regularly, please remeber
to send your $ to the authors, don't be a outlaw, and over all, don't be a LAMER !!!

---[ INTRO ]----------------------------------------------------------------------------------

target: Screen Loupe for Window95/NT v4.4
where : http://www.execpc.com/~sbd

Tools : SoftIce for Win9x v3.24
	W32Dasm v8.9
        Programming Language (C, Pascal, asm, anyone you want, I'll use our old C)

This is my third tutorial in english. I hope my bad spelling won't make this text too much 
hard to understand for you. :)

I'll try to teach you how to make a key generator for a program. The way i teach will be 
based more on reverse enginerring (instead of only cracking the program, we try to fully 
understand the whole key-generating algorithm), some newbies maybe having problem of 
reading this.

The protection scheme actually encode your name into certain format, and compare with two
possible encoded name, if it match it will register you directly without further checking on
your company and registration key. If it doesn't match then it will perform key-generating
process and compare the generated key with your fake key.

By reading the above paragraph, i think you should know there are many ways to crack this
program(byte patching, look at real key directly, reverse the code to find that two built-in
name...), but what i'm teaching here is the key-generator process so we are only interested
in building a key-generator.(but i'll still touch a bit on others method :))

If you want to unregister the program, delete the all keys in registry:
[HKEY_USERS\.Default\Software\Software by Design\Screen Loupe for Windows 95/NT\Registration]

I'll assume you know the following:

- basic use of SoftIce
- asm instructions (at least the ones used for cracking)
- knowing which call is important call

---[ TUTORIAL ]-------------------------------------------------------------------------------

At first, launch SoftICe (assuming you know the basics, and how to setup this Numega's
nice tool). Then launch our target, loupe.exe! Go to the help menu and select the register.
Enter a name and company.

Simplily put a breakpoint before you press ok(eg.bpx hmemcpy or others...).You should have
break into softice after pressing OK button. Keep pressing F12 until you get back to the 
traget program code. You will be in:

* Reference To: USER32.GetDlgItemTextA, Ord:0104h
                                  |
:004060FB 8B1D6C824100            mov ebx, dword ptr [0041826C]	;ebx is function GetDlgItemTextA
:00406101 57                      push edi
:00406102 6A32                    push 00000032
:00406104 56                      push esi
:00406105 6A65                    push 00000065
:00406107 55                      push ebp
:00406108 FFD3                    call ebx			;call to get our name
:0040610A 8D7E32                  lea edi, dword ptr [esi+32]
:0040610D 6A32                    push 00000032
:0040610F 57                      push edi
:00406110 6A66                    push 00000066
:00406112 55                      push ebp
:00406113 FFD3                    call ebx			;call to get our company
:00406115 8D442410                lea eax, dword ptr [esp+10]
:00406119 6800010000              push 00000100
:0040611E 50                      push eax

* Possible Ref to Menu: MenuID_03E8, Item: "System Information   Ctrl+S"
                                  |
:0040611F 6A67                    push 00000067
:00406121 55                      push ebp
:00406122 FFD3                    call ebx			;call to get our fake key
:00406124 8D4C2410                lea ecx, dword ptr [esp+10]

Until here you should have notice that the program use function GetDlgItemTextA to get our 
name, company and registration key. It move the function into ebx first, then call the 
function using 'call ebx' for 3 times. When you reach here, by typing d ecx you should see 
your fake registration key.


:00406128 51                      push ecx		;ecx=our fake key
:00406129 E83D9B0000              call 0040FC6B

The is a call that covert our our fake key from string form into hexadecimal format. The
converted result be in eax.(The registartion key can only takes in digits.)


:0040612E 56                      push esi		;esi=our name
:0040612F 8BD8                    mov ebx, eax		;move the result to ebx
:00406131 E8FA7C0000              call 0040DE30		;call that encode our name
:00406136 83C408                  add esp, 00000008
:00406139 3D92A71901              cmp eax, 0119A792	;compare encoded name with 119A792
:0040613E 7518                    jne 00406158

The call at line 406131 is very important, it has being call 3 times in this program. It is 
used to encode the data pushed in into certain format and return the result at eax. In the
above case, it encode our name and compare it with 119A792(certain encoded name). If it is
equal, then it will register you as the author "Grgory Braun" with correct registration key.
The following code is registering you as "Gregory Braun" with company name"Software Design",
(we neglect them here...)

.......
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040613E(C)
|
:00406158 3D3CCE5F0D              cmp eax, 0D5FCE3C	;compare our encoded name with 0D5FCE3C
:0040615D 750C                    jne 0040616B

If you want to do a byte-patching, then 40615D is a good place to patch, change the 750C into
9090, so that it can always go to 40615F.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406156(U)
|
:0040615F 57                      push edi		;edi=our company
:00406160 56                      push esi		;esi=our name
:00406161 E85A770000              call 0040D8C0		;calculate real key
:00406166 83C408                  add esp, 00000008
:00406169 8BD8                    mov ebx, eax		;real key to ebx

If our decoded name equal to either 119A792 or 0D5FCE3C, then it will goes to address 40615F.
From 40615F to 406169, it call the code generating function and put the result into ebx, ebx
originally is our fake key that uses to compare with the encoded result.



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040615D(C)
|
:0040616B 57                      push edi		;edi=our company
:0040616C 56                      push esi		;esi=our name
:0040616D E84E770000              call 0040D8C0		;call that calculate real key
:00406172 83C408                  add esp, 00000008	;stack correction
:00406175 3BD8                    cmp ebx, eax		;compare our key to real key
:00406177 5F                      pop edi
:00406178 741D                    je 00406197		;jump to success message
:0040617A 68CFEA0000              push 0000EACF		;error message

* Possible Reference to String Resource ID=05000: " Register Screen Loupe for Windows 95/NT"

If our didn't jump over the code in 40615F-406169, then the ebx=eax and we can jump over
error message. Look carefully at 406161 and 40616D, they are calling the same function, this
is the function that we are interested in.(in 406169, it move the result in ebx, so that ebx
always equal to eax, if we jump over those code, then ebx is still our fake key).
If you want to just any want to look for the real key then type '? eax' after after the call at
40616D. The positive decimal number will be our real registration key.


In order to make a key-generator we trace into 'call 0040D8C0':
* Referenced by a CALL at Addresses:
|:004058CD   , :00405FA3   , :00406161   , :0040616D   
|
:0040D8C0 8B442404                mov eax, dword ptr [esp+04]	;eax=name
:0040D8C4 56                      push esi
:0040D8C5 8B35E8F54100            mov esi, dword ptr [0041F5E8]	;esi=ABED0F00
:0040D8CB 50                      push eax
:0040D8CC 81CE78030000            or esi, 00000378		;esi=ABED0F00 or 378=ABED0F78
:0040D8D2 E859050000              call 0040DE30			;call that encode our name
:0040D8D7 8B4C2410                mov ecx, dword ptr [esp+10]	;ecx=company
:0040D8DB 03F0                    add esi, eax			;esi=esi+eax
:0040D8DD 51                      push ecx			;push company
:0040D8DE E84D050000              call 0040DE30			;call that encode our company
:0040D8E3 83C408                  add esp, 00000008		;stack correction
:0040D8E6 03C6                    add eax, esi			;eax=eax(encoded company)+esi
:0040D8E8 5E                      pop esi
:0040D8E9 C3                      ret

The above code basically very short and simple, the encode our name and company name using
'call 0040DE30' and add them together with ABEDOF78. It can be summarized as follow:
Real key = [encoded name] + [encode company] + ABEDOF78

If we noticed carefully the 'call 0040DE30' is called befero this at 406131, at that times it
is used to encode our name. Since it is the most important call, we trace into 'call 0040DE30':

* Referenced by a CALL at Addresses:
|:00406131   , :0040D8D2   , :0040D8DE   
|
:0040DE30 51                      push ecx
:0040DE31 53                      push ebx
:0040DE32 8B5C240C                mov ebx, dword ptr [esp+0C]	;ebx=value pushed in.(name/comp)
:0040DE36 56                      push esi			
:0040DE37 33F6                    xor esi, esi			;esi=0
:0040DE39 53                      push ebx
:0040DE3A 8974240C                mov dword ptr [esp+0C], esi	;clear [esp+0c]=place to store
								;our encoded result
* Reference To: KERNEL32.lstrlenA, Ord:0308h
                                  |
:0040DE3E FF153C814100            Call dword ptr [0041813C]	;get length of ebx, eax=result
:0040DE44 85DB                    test ebx, ebx
:0040DE46 744F                    je 0040DE97			;jump if no name/company enter
:0040DE48 85C0                    test eax, eax
:0040DE4A 744B                    je 0040DE97			;jump if length = 0
:0040DE4C 33D2                    xor edx, edx			;clear edx,edx is counter
:0040DE4E 85C0                    test eax, eax
:0040DE50 7E45                    jle 0040DE97			;jump if length = 0
:0040DE52 55                      push ebp
:0040DE53 57                      push edi

* Possible StringData Ref from Data Obj ->"|b!pz*ls;rn|lf$vi^Axpe)rx5aic&9/2m5lsi4@0dmZw9"
                                        ->"4cmqpfhw"
                                  |
:0040DE54 BE10C74100              mov esi, 0041C710	;esi=417C710,a place with random no.

[41C710] strore a lot of random number that is important in key-generating.
by typing d esi you will see:
XXXX:0041C710 72 62 21 70 7A 2A 6C 73-3B 72 6E 7C 6C 66 24 76
XXXX:0041C720 69 5E 41 78 70 65 29 72-78 35 61 69 63 ....
It is very important, please write them down if you want to make a keygen.


:0040DE59 BF01000000              mov edi, 00000001	;edi is also act as counter
:0040DE5E 2BF3                    sub esi, ebx		;esi=esi-ebx
:0040DE60 8BCB                    mov ecx, ebx		;ecx=ebx
:0040DE62 2BFB                    sub edi, ebx		;edi=edi-ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040DE8D(C)
|
:0040DE64 0FBE1C0E                movsx ebx, byte ptr [esi+ecx]		;ebx=[41C710+edx]
:0040DE68 0FBEAC10D8C64100        movsx ebp, byte ptr [eax+edx+0041C6D8];ebp=[41C6D8+edx+eax]

[41C6D8] also a set of random number that are very important. By typing 'd 41C6D8', you see:
XXXX:41C6D8 23 73 65 72 42 26 6E 7A-7C 6D 66 4D 31 2F 35 28
XXXX:41C6E8 21 73 64 24 4D 71 2E 7B-73 5D 2B 73 46 6A 74 4B
.....
Please write them down also if you want to make a keygen.


:0040DE70 0FAFDD                  imul ebx, ebp			;ebx=ebx*ebp
:0040DE73 8D2C0F                  lea ebp, dword ptr [edi+ecx]	;ebp=edx+1
:0040DE76 0FAFDD                  imul ebx, ebp			;ebx=ebx*(edx+1)
:0040DE79 0FBE29                  movsx ebp, byte ptr [ecx]	;ebp=one byte from name/company
:0040DE7C 0FAFDD                  imul ebx, ebp			;ebx=ebx*ebp
:0040DE7F 8B6C2410                mov ebp, dword ptr [esp+10]	;ebp=[esp+10]
:0040DE83 03EB                    add ebp, ebx			;ebp=ebp*ebx
:0040DE85 42                      inc edx			;increase counter
:0040DE86 41                      inc ecx			;increase address of name/comp 
:0040DE87 3BD0                    cmp edx, eax			;comapre counter with length
:0040DE89 896C2410                mov dword ptr [esp+10], ebp	;move result to [esp+10]
:0040DE8D 7CD5                    jl 0040DE64			;jump if counter
#include

int count1;
char ran1[20]={0x7c,0x62,0x21,0x70,0x7a,0x2a,0x6c,0x73,0x3b,0x72,0x6e,0x7c,0x6c,0x66,0x24,0x76,0x69,0x5e,0x41,0x78};
char ran2[20]={0x23,0x73,0x65,0x72,0x42,0x26,0x6e,0x7a,0x7c,0x6d,0x66,0x4d,0x31,0x2f,0x35,0x28,0x21,0x73,0x64,0x24};
long encode(char [],int);	//call that similar to 'call 40DE30'

int main(void)
  {
   long code=0xabed0f78;	//the esi result in line 40D8CC
   int length;
   char name[20],comp[20];
   clrscr();
   textcolor(14);
   cprintf("    __,__\r\n");
   cprintf("   /     \\\r\n" );
   cprintf("   vvvvvvv  /|__/|\r\n");
   cprintf("      I   /O,O   |\r\n");
   cprintf("      I /_____   |      /|/|\r\n");
   cprintf("     J|/^ ^ ^ \\  |    /00  |    _//|\r\n");
   cprintf("      |^ ^ ^ ^ |W|   |/^^\\ |   /oo |\r\n");
   cprintf("       \\m___m__|_|    \\m_m_|   \\mm_|\r\n");
   textcolor(10);
   cprintf("===================================================");
   textcolor(11);
   cprintf("\r\nKeyGenerator - Screen Loupe for Windows95/NT v4.4");
   textcolor(10);
   cprintf("\r\n===================================================");
   printf("\nCracked by ");
   textcolor(14);
   cprintf("%c%c%c",0x10,0x10,0x10);
   textcolor(12);
   cprintf("Yes123");
   textcolor(14);
   cprintf("%c%c%c",0x11,0x11,0x11);
   printf(" - March 1999");
   printf("\n\nEnter register name (1-20 chars)= ");	//it can be more if you use more value
   scanf("%[^\n]",name);				//of [41C710],i used only 20.
   getchar();
   printf("Enter register company (1-10 chars)= ");	//it can be more if you use more value
   scanf("%[^\n]",comp);				//of [41C6D8], i used only 20.
   for (length=0;name[length]>0;length++);	//calculate length of our name
   code=code+encode(&name,length);
   for (length=0;comp[length]>0;length++);	//calculate length of our company name
   code=code+encode(&comp,length);
   printf("Your registration key = %lu",code);
   return ;
}

long encode(char code[],int length){		//same as 'call 40DE30'
  long key=0,result=0;
  for (count1=0;code[count1]>0;count1++){
    key=ran1[count1];
    key=key*ran2[count1+length];
    key=key*(count1+1);
    key=key*code[count1];
    result=result+key;
    }
  return result;
  }

---[ LAST ]--------------------------------------------------------------------------------------

I know my english expressing ability is weak, so in many place i know what's happening but 
i cann't express well or explain to you clearly. I hope you can really try it out then you can
understand more out of it. You can also try to reverse encoded name of 119A792 or 0D5FCE3C,
see what name correspound to this value. It should have many possibility(like UNIX password), 
but you can try it out to improve your reverse enginering skill.

Thanks for reading my keygen tutorial.

---[ THAT'S ALL FOLKS ]-----------------------------------------------------------------------
   __,__
  /     \       
  vvvvvvv  /|__/|
     I   /O,O   |       
     I /_____   |
    J|/^ ^ ^ \  |
     |^ ^ ^ ^ |W|
      \m___m__|_|Yes123 '99